import { Body, Inject, Provide } from '@midwayjs/core';
import { NumEntity, NumStatus } from '../entity/num.entity';
import { In, Repository } from 'typeorm';
import { InjectEntityModel } from '@midwayjs/typeorm';
import Utils from '../utils';
import { Seller } from '../entity/seller.entity';
import { AssignNumDto, NumPageQueryDto } from '../dto/num.dto';

@Provide()
export class NumService {
  @InjectEntityModel(NumEntity)
  numModel: Repository<NumEntity>;

  @InjectEntityModel(Seller)
  sellerModel: Repository<Seller>;

  @Inject()
  utils: Utils;

  /**
   * 添加编号
   * @param min 编号范围最小值
   * @param max 编号范围最大值
   * @returns
   */
  async addNums(min: number, max?: number) {
    // 根据min和max批量生成编号
    // 需要判断min-max范围内是否有重复编号
    // 如果max为空，则默认max等于min
    // 如果数据库中已存在min-max范围内的编号，将存在的编号剔除
    // 插入数据库中没有的编号即可
    if (!max) {
      max = min;
    }
    if (min > max) {
      return this.utils.response.fail('min必须小于等于max');
    }
    // 生成编号
    const nums: string[] = [];
    for (let i = min; i <= max; i++) {
      nums.push(i.toString());
    }
    // 查询数据库已存在的编号
    const existNums = await this.numModel.find({
      where: {
        num: In(nums)
      }
    });
    const existNumSet = new Set(existNums.map(n => n.num));
    // 剔除已存在的编号
    const newNums = nums.filter(n => !existNumSet.has(n));
    if (newNums.length === 0) {
      return this.utils.response.fail('该范围内编号均已存在，无需插入');
    }
    // 插入数据库中没有的编号
    const entities = newNums.map(n => {
      const entity = new NumEntity();
      entity.num = n;
      entity.status = NumStatus.AVAILABLE;
      entity.create_at = Date.now();
      entity.update_at = Date.now();
      return entity;
    });
    await this.numModel.insert(entities);
    return this.utils.response.success(
      entities,
      `成功插入${entities.length}个编号`
    );
  }

  /**
   * 分配编号
   * @param nums 编号数组
   * @param sellerId 经销商ID
   * @returns
   */
  async assignNums(dto: AssignNumDto) {
    const { adds, rems, sellerId } = dto;
    const seller = await this.sellerModel.findOne({ where: { id: sellerId } });
    if (!seller) {
      return this.utils.response.fail('经销商不存在');
    }

    // 查询所有涉及的编号
    const allIds = [...adds, ...rems];
    const nums = await this.numModel.find({
      where: { id: In(allIds) },
      relations: ['seller']
    });

    // 处理 adds
    const canAssign = nums.filter(
      n => adds.includes(n.id) && n.status === NumStatus.AVAILABLE
    );
    // 处理 rems
    const canRemove = nums.filter(
      n =>
        rems.includes(n.id) &&
        n.status === NumStatus.ASSIGNED &&
        n.seller?.id === sellerId
    );

    // 批量更新
    await this.numModel.update(
      { id: In(canRemove.map(n => n.id)) },
      { status: NumStatus.AVAILABLE, seller: null }
    );

    await this.numModel.update(
      { id: In(canAssign.map(n => n.id)) },
      { status: NumStatus.ASSIGNED, seller }
    );

    return this.utils.response.success(
      {
        assigned: canAssign.map(n => n.id),
        removed: canRemove.map(n => n.id)
      },
      `成功分配${canAssign.length}个编号，解除${canRemove.length}个编号的分配`
    );
  }

  /**
   * 查询可用编号
   * @returns
   */
  async getAvailableNums() {
    const qb = this.numModel
      .createQueryBuilder('num')
      .where('num.status = :status', { status: NumStatus.AVAILABLE })
      .orderBy('CAST(num.num AS UNSIGNED)', 'ASC');
    const nums = await qb.getMany();
    return this.utils.response.success(
      nums,
      `成功查询${nums.length}个可用编号`
    );
  }

  /**
   * 查询已分配编号
   * @param sellerId 经销商ID
   * @returns
   */
  async getAssignedNumbers(sellerId?: number) {
    const qb = this.numModel
      .createQueryBuilder('num')
      .where('num.status IN (:...status)', {
        status: [NumStatus.ASSIGNED, NumStatus.LOCKED, NumStatus.FINISHED]
      });
    if (sellerId) {
      qb.andWhere('num.seller_id = :sellerId', { sellerId });
    }
    qb.orderBy('num.status', 'ASC').addOrderBy(
      'CAST(num.num AS UNSIGNED)',
      'ASC'
    );
    const nums = await qb.getMany();
    return this.utils.response.success(
      nums,
      `成功查询${nums.length}个已分配编号`
    );
  }

  async getNumPageList(
    @Body()
    dto: NumPageQueryDto
  ) {
    const { status, sellerId } = dto;
    const current = dto.current - 0;
    const pageSize = dto.pageSize - 0;
    const where: { status?: NumStatus; seller?: Seller } = {};
    if (status) {
      where.status = status;
    }
    if (sellerId) {
      const seller = await this.sellerModel.findOne({
        where: {
          id: sellerId
        }
      });
      if (seller) {
        where.seller = seller;
      }
    }
    const [list, total] = await this.numModel.findAndCount({
      where: where as any,
      skip: (current - 1) * pageSize,
      take: pageSize,
      order: {
        id: 'DESC'
      },
      relations: ['seller']
    });
    return this.utils.response.success(
      {
        list,
        total,
        current,
        pageSize
      },
      `成功查询${total}个可用编号`
    );
  }

  async getMaxNumber() {
    const max = await this.numModel
      .createQueryBuilder('num')
      .orderBy('CAST(num.num AS UNSIGNED)', 'DESC')
      .getOne();
    return this.utils.response.success(
      max || null,
      `成功查询最大编号：${max?.num || 'null'}`
    );
  }
}
